package com.boil.qz.safekavass.dao;

import com.boil.util.Constants;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Repository;

import javax.persistence.*;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaDelete;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.CriteriaUpdate;
import javax.persistence.metamodel.Metamodel;
import java.util.List;
import java.util.Map;

/**
 * Created by ChenYong on 2017-07-06.
 * <br>
 * Jpa Dao。
 * <br>
 * <p style="color: red;">全面代替 Hibernate。</p>
 */
@Repository
public class JpaDao {
    /**
     * 注入 Jpa 实例管理器
     */
    @PersistenceContext
    private EntityManager entityManager;

    /**
     * 获取 Jpa 实例管理器。
     *
     * @return Jpa 实例管理器
     */
    public EntityManager getEntityManager() {
        return entityManager;
    }

    /**
     * 持久化实例。
     *
     * @param entity 实例
     */
    public <T> void persist(T entity) {
        if (entity != null) {
            entityManager.persist(entity);
        }
    }

    /**
     * 持久化或更新实例。
     *
     * @param entity 实例
     * @return 托管状态的实例
     */
    public <T> T merge(T entity) {
        if (entity == null) {
            return null;
        }

        return entityManager.merge(entity);
    }

    /**
     * 删除实例。
     *
     * @param entity 托管状态的实例
     */
    public void remove(Object entity) {
        if (entity != null) {
            entityManager.remove(entity);
        }
    }

    /**
     * 查询实例。
     *
     * @param entityClass 实例类类型
     * @param primaryKey  主键
     * @return 托管状态的实例
     */
    public <T> T find(Class<T> entityClass, Object primaryKey) {
        if ((entityClass == null) || (primaryKey == null)) {
            return null;
        }

        return entityManager.find(entityClass, primaryKey);
    }

    /**
     * 查询实例。
     *
     * @param entityClass 实例类类型
     * @param primaryKey  主键
     * @param properties  ？？？
     * @return 托管状态的实例
     */
    public <T> T find(Class<T> entityClass, Object primaryKey, Map<String, Object> properties) {
        if ((entityClass == null) || //
                (primaryKey == null) || //
                (properties == null) || //
                properties.isEmpty()) {
            return null;
        }

        return entityManager.find(entityClass, primaryKey, properties);
    }

    /**
     * 查询实例。
     *
     * @param entityClass 实例类类型
     * @param primaryKey  主键
     * @param lockMode    锁模式
     * @return 托管状态的实例
     */
    public <T> T find(Class<T> entityClass, Object primaryKey, LockModeType lockMode) {
        if ((entityClass == null) || //
                (primaryKey == null) || //
                (lockMode == null)) {
            return null;
        }

        return entityManager.find(entityClass, primaryKey, lockMode);
    }

    /**
     * 查询实例。
     *
     * @param entityClass 实例类类型
     * @param primaryKey  主键
     * @param lockMode    锁模式
     * @param properties  ？？？
     * @return 托管状态的实例
     */
    public <T> T find(Class<T> entityClass, Object primaryKey, LockModeType lockMode, Map<String, Object> properties) {
        if ((entityClass == null) || //
                (primaryKey == null) || //
                (lockMode == null) || //
                (properties == null) || //
                properties.isEmpty()) {
            return null;
        }

        return entityManager.find(entityClass, primaryKey, lockMode, properties);
    }

    /**
     * 获取代理实例，并没有去数据库中查询。
     *
     * @param entityClass 实例类类型
     * @param primaryKey  主键
     * @return 代理实例
     */
    public <T> T getReference(Class<T> entityClass, Object primaryKey) {
        if ((entityClass == null) || (primaryKey == null)) {
            return null;
        }

        return entityManager.getReference(entityClass, primaryKey);
    }

    /**
     * 同步数据库。
     */
    public void flush() {
        entityManager.flush();
    }

    /**
     * 设置同步模式。
     *
     * @param flushMode 同步模式
     */
    public void setFlushMode(FlushModeType flushMode) {
        if (flushMode != null) {
            entityManager.setFlushMode(flushMode);
        }
    }

    /**
     * 获取同步模式。
     *
     * @return 同步模式
     */
    public FlushModeType getFlushMode() {
        return entityManager.getFlushMode();
    }

    /**
     * 给实例上锁。
     *
     * @param entity   实例
     * @param lockMode 锁模式
     */
    public void lock(Object entity, LockModeType lockMode) {
        if ((entity != null) && (lockMode != null)) {
            entityManager.lock(entity, lockMode);
        }
    }

    /**
     * 给实例上锁。
     *
     * @param entity     实例
     * @param lockMode   锁模式
     * @param properties ？？？
     */
    public void lock(Object entity, LockModeType lockMode, Map<String, Object> properties) {
        if ((entity != null) && //
                (lockMode != null) && //
                (properties != null) && //
                !properties.isEmpty()) {
            entityManager.lock(entity, lockMode, properties);
        }
    }

    /**
     * 刷新实例，使之与数据库中的数据一致。
     *
     * @param entity 托管状态的实例
     */
    public void refresh(Object entity) {
        if (entity != null) {
            entityManager.refresh(entity);
        }
    }

    /**
     * 刷新实例，使之与数据库中的数据一致。
     *
     * @param entity     托管状态的实例
     * @param properties ？？？
     */
    public void refresh(Object entity, Map<String, Object> properties) {
        if ((entity != null) && //
                (properties != null) && //
                !properties.isEmpty()) {
            entityManager.refresh(entity, properties);
        }
    }

    /**
     * 刷新实例，使之与数据库中的数据一致。
     *
     * @param entity   托管状态的实例
     * @param lockMode 锁模式
     */
    public void refresh(Object entity, LockModeType lockMode) {
        if ((entity != null) && (lockMode != null)) {
            entityManager.refresh(entity, lockMode);
        }
    }

    /**
     * 刷新实例，使之与数据库中的数据一致。
     *
     * @param entity     托管状态的实例
     * @param lockMode   锁模式
     * @param properties ？？？
     */
    public void refresh(Object entity, LockModeType lockMode, Map<String, Object> properties) {
        if ((entity != null) && //
                (lockMode != null) && //
                (properties != null) && //
                !properties.isEmpty()) {
            entityManager.refresh(entity, lockMode, properties);
        }
    }

    /**
     * 将所有托管状态的实例变为游离状态的实例。
     */
    public void clear() {
        entityManager.clear();
    }

    /**
     * 将实例由托管状态变为游离状态。
     *
     * @param entity 托管状态的实例
     */
    public void detach(Object entity) {
        if (entity != null) {
            entityManager.detach(entity);
        }
    }

    /**
     * 判断实例是否为托管状态。
     *
     * @param entity 实例
     * @return <ol>
     * <li>true-是；</li>
     * <li>false-否。</li>
     * </ol>
     */
    public boolean contains(Object entity) {
        if (entity == null) {
            return Constants.VALUE_FALSE;
        }

        return entityManager.contains(entity);
    }

    /**
     * 获取实例的锁模式。
     *
     * @param entity 托管状态的实例
     * @return 锁模式
     */
    public LockModeType getLockMode(Object entity) {
        if (entity == null) {
            return null;
        }

        return entityManager.getLockMode(entity);
    }

    /**
     * 设置实例管理器的属性或提示。
     *
     * @param propertyName 属性名称
     * @param value        属性值
     */
    public void setProperty(String propertyName, Object value) {
        if (StringUtils.isNotBlank(propertyName)) {
            entityManager.setProperty(propertyName, value);
        }
    }

    /**
     * 获取实例管理器的属性或提示。
     *
     * @return 实例管理器的属性或提示
     */
    public Map<String, Object> getProperties() {
        return entityManager.getProperties();
    }

    /**
     * 创建查询实例。
     *
     * @param qlString Java 持久化查询语句
     * @return 查询实例
     */
    public Query createQuery(String qlString) {
        if (StringUtils.isBlank(qlString)) {
            return null;
        }

        return entityManager.createQuery(qlString);
    }


    /**
     * 创建查询实例。
     *
     * @param criteriaQuery Java 持久化标准查询语句
     * @return 查询实例
     */
    public <T> TypedQuery<T> createQuery(CriteriaQuery<T> criteriaQuery) {
        if (criteriaQuery == null) {
            return null;
        }

        return entityManager.createQuery(criteriaQuery);
    }

    /**
     * 创建查询实例。
     *
     * @param updateQuery Java 持久化标准更新语句
     * @return 查询实例
     */
    public Query createQuery(CriteriaUpdate updateQuery) {
        if (updateQuery == null) {
            return null;
        }

        return entityManager.createQuery(updateQuery);
    }

    /**
     * 创建查询实例。
     *
     * @param deleteQuery Java 持久化标准删除语句
     * @return 查询实例
     */
    public Query createQuery(CriteriaDelete deleteQuery) {
        if (deleteQuery == null) {
            return null;
        }

        return entityManager.createQuery(deleteQuery);
    }

    /**
     * 创建查询实例。
     *
     * @param qlString    Java 持久化查询语句
     * @param resultClass 实例类类型
     * @return 查询实例
     */
    public <T> TypedQuery<T> createQuery(String qlString, Class<T> resultClass) {
        if (StringUtils.isBlank(qlString) || (resultClass == null)) {
            return null;
        }

        return entityManager.createQuery(qlString, resultClass);
    }

    /**
     * 创建查询实例。
     *
     * @param name Java 持久化查询语句的名称
     * @return 查询实例
     */
    public Query createNamedQuery(String name) {
        if (StringUtils.isBlank(name)) {
            return null;
        }

        return entityManager.createNamedQuery(name);
    }

    /**
     * 创建查询实例。
     *
     * @param name        Java 持久化查询语句的名称
     * @param resultClass 实例类类型
     * @return 查询实例
     */
    public <T> TypedQuery<T> createNamedQuery(String name, Class<T> resultClass) {
        if (StringUtils.isBlank(name) || (resultClass == null)) {
            return null;
        }

        return entityManager.createNamedQuery(name, resultClass);
    }

    /**
     * 创建查询实例。
     *
     * @param sqlString SQL 语句
     * @return 查询实例
     */
    public Query createNativeQuery(String sqlString) {
        if (StringUtils.isBlank(sqlString)) {
            return null;
        }

        return entityManager.createNativeQuery(sqlString);
    }

    /**
     * 创建查询实例。
     *
     * @param sqlString   SQL 语句
     * @param resultClass 实例类类型
     * @return 查询实例
     */
    public Query createNativeQuery(String sqlString, Class resultClass) {
        if (StringUtils.isBlank(sqlString) || (resultClass == null)) {
            return null;
        }

        return entityManager.createNativeQuery(sqlString, resultClass);
    }

    /**
     * 创建查询实例。
     *
     * @param sqlString        SQL 语句
     * @param resultSetMapping 结果集映射的名称
     * @return 查询实例
     */
    public Query createNativeQuery(String sqlString, String resultSetMapping) {
        if (StringUtils.isBlank(sqlString) || (StringUtils.isBlank(resultSetMapping))) {
            return null;
        }

        return entityManager.createNativeQuery(sqlString, resultSetMapping);
    }

    /**
     * 创建存储过程查询实例。
     *
     * @param name ？？？
     * @return 存储过程查询实例
     */
    public StoredProcedureQuery createNamedStoredProcedureQuery(String name) {
        if (StringUtils.isBlank(name)) {
            return null;
        }

        return entityManager.createNamedStoredProcedureQuery(name);
    }

    /**
     * 创建存储过程查询实例。
     *
     * @param procedureName 存储过程的名称
     * @return 存储过程查询实例
     */
    public StoredProcedureQuery createStoredProcedureQuery(String procedureName) {
        if (StringUtils.isBlank(procedureName)) {
            return null;
        }

        return entityManager.createStoredProcedureQuery(procedureName);
    }

    /**
     * 创建存储过程查询实例。
     *
     * @param procedureName 存储过程的名称
     * @param resultClasses 实例类类型
     * @return 存储过程查询实例
     */
    public StoredProcedureQuery createStoredProcedureQuery(String procedureName, Class... resultClasses) {
        if (StringUtils.isBlank(procedureName) || //
                (resultClasses == null) || //
                (resultClasses.length == Constants.VALUE_0)) {
            return null;
        }

        return entityManager.createStoredProcedureQuery(procedureName, resultClasses);
    }

    /**
     * 创建存储过程查询实例。
     *
     * @param procedureName     存储过程的名称
     * @param resultSetMappings 多个结果集映射的名称
     * @return 存储过程查询实例
     */
    public StoredProcedureQuery createStoredProcedureQuery(String procedureName, String... resultSetMappings) {
        if (StringUtils.isBlank(procedureName) || //
                (resultSetMappings == null) || //
                (resultSetMappings.length == Constants.VALUE_0)) {
            return null;
        }

        return entityManager.createStoredProcedureQuery(procedureName, resultSetMappings);
    }

    /**
     * 加入事务。
     */
    public void joinTransaction() {
        entityManager.joinTransaction();
    }

    /**
     * 判断是否加入事务。
     *
     * @return <ol>
     * <li>true-是；</li>
     * <li>false-否。</li>
     * </ol>
     */
    public boolean isJoinedToTransaction() {
        return entityManager.isJoinedToTransaction();
    }

    /**
     * 获取 Jpa 底层的供应商 API。
     *
     * @param cls 实现 Jpa 底层的供应商 API 类类型
     * @return 实现 Jpa 底层的供应商 API 实例
     */
    public <T> T unwrap(Class<T> cls) {
        if (cls == null) {
            return null;
        }

        return entityManager.unwrap(cls);
    }

    /**
     * 获取 Jpa 底层持久化的供应商引用。
     *
     * @return Jpa 底层持久化的供应商引用
     */
    public Object getDelegate() {
        return entityManager.getDelegate();
    }

    /**
     * 关闭实例管理器。
     */
    public void close() {
        entityManager.close();
    }

    /**
     * 判断实例管理器是否打开。
     *
     * @return <ol>
     * <li>true-是；</li>
     * <li>false-否。</li>
     * </ol>
     */
    public boolean isOpen() {
        return entityManager.isOpen();
    }

    /**
     * 获取实例事务。
     *
     * @return 实例事务
     */
    public EntityTransaction getTransaction() {
        return entityManager.getTransaction();
    }

    /**
     * 获取实例管理器工厂。
     *
     * @return 实例管理器工厂
     */
    public EntityManagerFactory getEntityManagerFactory() {
        return entityManager.getEntityManagerFactory();
    }

    /**
     * 获取标准查询工厂。
     *
     * @return 标准查询工厂
     */
    public CriteriaBuilder getCriteriaBuilder() {
        return entityManager.getCriteriaBuilder();
    }

    /**
     * 获取元模型。
     *
     * @return 元模型
     */
    public Metamodel getMetamodel() {
        return entityManager.getMetamodel();
    }

    /**
     * 创建实例图（主要用于延迟加载）。
     *
     * @param rootType 实例图类类型
     * @return 实例图
     */
    public <T> EntityGraph<T> createEntityGraph(Class<T> rootType) {
        if (rootType == null) {
            return null;
        }

        return entityManager.createEntityGraph(rootType);
    }

    /**
     * 创建实例图（主要用于延迟加载）。
     *
     * @param graphName 实例图的名称
     * @return 实例图
     */
    public EntityGraph<?> createEntityGraph(String graphName) {
        if (StringUtils.isBlank(graphName)) {
            return null;
        }

        return entityManager.createEntityGraph(graphName);
    }

    /**
     * 获取实例图（主要用于延迟加载）。
     *
     * @param graphName 实例图的名称
     * @return 实例图
     */
    public EntityGraph<?> getEntityGraph(String graphName) {
        if (StringUtils.isBlank(graphName)) {
            return null;
        }

        return entityManager.getEntityGraph(graphName);
    }

    /**
     * 获取实例图 <code>List</code>（主要用于延迟加载）。
     *
     * @param entityClass 实例类类型
     * @return 实例图 <code>List</code>
     */
    public <T> List<EntityGraph<? super T>> getEntityGraphs(Class<T> entityClass) {
        if (entityClass == null) {
            return null;
        }

        return entityManager.getEntityGraphs(entityClass);
    }
}